home *** CD-ROM | disk | FTP | other *** search
- #include "datapriv.hpp"
-
- int recstrcmp(void *,void *);
-
- /********************* Accessors ********************************/
-
- char *record::indname()
- {
- if (oi) return oi->name;
- return 0;
- }
-
-
- /********************* RECORD FUNCTIONS *************************/
-
- // This is the constructor for a record, which grabs the space
- // for it
-
- /********************* CONSTRUCTOR *****************************/
-
- record::record(database &dbp,char *indname)
- {
- if (!(recbuf=new char[dbp.reclen+1]) ||
- !(recbufo=new char[dbp.reclen+1]) ||
- !(fieldwork=new char[dbp.maxfieldl+1]))
- dbfer(NORECSP);
-
- if (dbp.isvalid()) {dbfer(INVDB); return;}
-
- memset(recbuf,' ',dbp.reclen+1); // Clear record
- memset(recbufo,' ',dbp.reclen+1);
- rbp=recbuf;
-
- db=&dbp;
- rn=-1; // Indicate no record has been read into recbuf
- delstate=NOTDEL;
-
- ltype=-1; // Flag no last key found
- curind=0;
- nextind=0;
-
- next=dbp.firstrec; // Link into record tree
- dbp.firstrec=this;
- prev=0;
-
- // Now check for index, if found then copy in top cluster
-
- oi=0;
-
- if (oi=dbp.findex)
- {
- if (indname) oi=dbp.getindex(indname);
-
- if (oi)
- {
- nextind=oi->firstrec; // Link into index tree
- oi->firstrec=this;
- curind=new indpt(oi->topind);
- }
- }
- }
-
- /********************** DESTRUCTOR *****************************/
-
- // This is the destructor for a record, which also cleans up the pointers
-
- record::~record(void)
- {
- if (oi)
- {
- record *rp,*fp;
- fp=rp=oi->firstrec;
- while(rp)
- {
- if (rp==this)
- {
- if (fp==rp) oi->firstrec=nextind;
- else {while(fp->nextind!=rp) fp=fp->nextind; fp->nextind=nextind;}
- break;
- }
- rp=rp->nextind;
- }
- }
- killind();
- if (recbuf) delete recbuf;
- if (recbufo) delete recbufo;
- if (fieldwork) delete fieldwork;
- if (prev) prev->next=next; else db->firstrec=next;
- if (next) next->prev=prev;
- }
-
- // Kill all indclus parents of the record
-
- void record::killind(void)
- {
- indpt *pt,*npt;
-
- if (curind) // Delete all references to current index
- {
- pt=curind;
- do
- {
- npt=pt->parent; delete pt; pt=npt;
- }
- while (pt);
- }
- }
-
- /********************* Record Assignment ***************/
-
- void record::operator=(record &s)
- {
- indpt *pt,*npt;
-
- if (curind)
- {
- killind();
- curind=new indpt(s.curind->icp); curind->currec=s.curind->currec;
-
- pt=(s.curind)->parent;
- npt=curind;
- while (pt)
- {
- npt->parent=new indpt(pt->icp); npt->currec=pt->currec;
- npt=npt->parent; pt=pt->parent;
- }
- }
- delstate=s.delstate;
- rn=s.rn;
- rbp=recbuf;
- indflg=s.indflg;
- oi=s.oi;
- memmove(lkey,s.lkey,128); ltype=s.ltype; lseltype=s.lseltype;
- memmove(recbuf,s.recbuf,db->reclen+1);
- memmove(recbufo,s.recbuf,db->reclen+1);
- memmove(fieldwork,s.fieldwork,db->maxfieldl+1);
- }
-
- /********************* SET the delete state ********************/
-
- void record::setdelstate(int sval)
- {
- if (sval!=DEL && sval!=NOTDEL) return;
-
- delstate=sval;
- *recbuf=(sval==DEL) ? '*' : ' ';
- }
-
- /********************* SELECT record n from dbf ****************/
-
- int record::seldbf(long n)
- {
- return select(n,ALL,1);
- }
-
- /********************* SELECT a record *************************/
-
- // Select a record from the data file
-
- int record::select(long n,int type,int dbfrec)
- {
- long ln=n; // Next Record
- long fp;
-
- if (n>0) // Select by record number
- {
- int rv;
-
- if (type==ALL && (!curind || dbfrec)) // Fast select direct from dbf
- {
- if (n<1 || n>db->nrec) return CANTSEL;
- rn=n;
- fp=db->recstart+db->reclen*(rn-1); Fseek(db->dbfp,fp,SEEK_SET);
- Fread(recbuf,db->reclen,1,db->dbfp);
- memmove(recbufo,recbuf,db->reclen+1);
- }
- else
- {
- rv=select(FIRST,type); if (rv) return rv;
- for(long i=1; i<n; i++) {rv=select(NEXT,type); if (rv) return rv;}
- }
- }
- else // Select FIRST, LAST, NEXT or PREVIOUS
- do
- {
- if (curind)
- {
- long tn;
-
- if (!(tn=getind(ln))) return CANTSEL;
- rn=tn;
- }
- else
- {
- if ((rn<=1 && ln==PREVIOUS) || (rn>=db->nrec && ln==NEXT)) return CANTSEL;
- switch(ln)
- {
- case FIRST : rn=1; break;
- case LAST : rn=db->nrec; break;
- case NEXT : rn++; break;
- case PREVIOUS : rn--; break;
- }
- }
-
- fp=db->recstart+db->reclen*(rn-1);
- Fseek(db->dbfp,fp,SEEK_SET);
- Fread(recbuf,db->reclen,1,db->dbfp); // Read the record
- memmove(recbufo,recbuf,db->reclen+1);
- if (n==FIRST) ln=NEXT; // If deleted, which record next
- if (n==LAST) ln=PREVIOUS;
- }
- while((type==DEL && *rbp==' ') || (type==NOTDEL && *rbp=='*'));
-
- delstate=(*rbp=='*') ? DEL : NOTDEL;
-
- return 0;
- }
-
- /********************* RECORD::SELECT - By Values ************/
-
- // This is for finding records where the expression is true
-
- int record::select(char *expr,long n,int type)
- {
- long ln=n;
- int i;
- int rv,rt;
- char ws[128];
-
- if (n>0)
- {
- rv=select(expr,FIRST,type); if (rv) return rv;
- for(i=1; i<n; i++)
- {
- if (rv=select("",NEXT,type)) return rv;
- }
- return(0);
- }
-
- if (rv=select(n,type)) return rv; // Position at first possible record
- if (n==FIRST) ln=NEXT;
- if (n==LAST) ln=PREVIOUS;
- if (*expr) eval(expr,ws,rv); // Tokenise expression if not already
-
- while(1)
- {
- rv=eval(ws,rt);
- if (!rv || rt!=OPLOG) return CANTSEL;
- if (*ws=='T') return(0);
- if (rv=select(ln,type)) return(rv);
- }
- }
-
- // This is for numbers, call with record::compnum
- // which compares two numbers
-
- int record::select(int fieldnum,int value,long n,int type)
- {
- return(select(fieldnum,&value,compnum,n,type));
- }
-
- int compnum(void *field,void *num)
- {
- return(atoi((char *)field)!=*(int *)num);
- }
-
- // First function is string, simply call user defined select with
- // the strcmp function
-
- int record::select(int fieldnum,char *value,long n,int type)
- {
- return(select(fieldnum,value,recstrcmp,n,type));
- }
-
- int recstrcmp(void *s1,void *s2)
- {
- return(strcmp(trim((char *)s1),trim((char *)s2)));
- }
-
- // This is the user defined select function which allows the
- // user to define a function to compare a field with a value,
- // and then selects those record for which the function returns
- // 0
-
- int record::select(int fieldnum,void *value,
- int (*cmp)(void *,void *),long n,int type)
- {
- long ln=n;
- field *fp;
- int i;
- int rv;
-
- if (n>0)
- {
- select(fieldnum,value,cmp,FIRST,type);
- for(i=1; i<n; i++)
- {
- if (rv=select(fieldnum,value,cmp,NEXT,type)) return rv;
- }
- return(0);
- }
-
- if (!(fp=db->getfield(fieldnum))) return CANTSEL;
-
- if (rv=select(n,type)) return rv; // Position at first possible record
- if (n==FIRST) ln=NEXT;
- if (n==LAST) ln=PREVIOUS;
-
- while(1)
- {
- strncpy(fieldwork,rbp+fp->recpos,fp->len);
- *(fieldwork+fp->len)=0;
- if (!(*cmp)(fieldwork,value)) return(0);
- if (rv=select(ln,type)) return(rv);
- }
- }
-
- /********************* Field Operations on the record *********/
-
- // This is overloaded, the 1st function returns by field number
-
- // Get field by field number
-
- char *record::getfield(int n,int trimflag)
- {
- field *fld;
-
- if (n<1 || n>db->nfield || rn<0)
- {
- memset(fieldwork,' ',db->maxfieldl); fieldwork[db->maxfieldl]=0;
- }
- else
- {
- fld=db->getfield(n);
- strncpy(fieldwork,rbp+fld->recpos,fld->len);
- *(fieldwork+fld->len)=0;
- if (fld->gettype()=='M') // Memo Field...
- {
- if (*fieldwork=='~') // New memo written
- {
- char *rv=*(char **)(rbp+fld->recpos+1);
- return rv;
- }
- long bn=atol(fieldwork);
- char *memow=db->memow; // Local copies of db variables
- int memowl=db->memowl;
- FILE *dbtp=db->dbtp;
-
- if (bn)
- {
- char *ep; // end of memo
- char *cbp=memow; // Current block pointer
- int ef=0; // Flag end of memo found
-
- if (!memow) memow=new char[512];
-
- Fseek(dbtp,bn*512L,SEEK_SET);
- for(int i=0; i<memowl; i++) // Read blocks until end found
- {
- Fread(cbp,512,1,dbtp);
- if (ep=strstr(memow,"\x1a\x1a")) {*ep=0; ef=1; break;}
- cbp+=512;
- }
- if (feof(dbtp) && !ef) {dbfer(INVMEMO); return ("");} // Invalid memo
- if (!ef) // Need to find new memo length
- {
- memowl=0;
- Fseek(dbtp,bn*512L,SEEK_SET);
- do
- {
- memowl++;
- Fread(memow,1,512,dbtp);
- if (ep=strstr(memow,"\x1a\x1a")) {*ep=0; ef=1;}
- }
- while(!ef && !feof(dbtp));
- if (memowl>1) {free(memow); memow=new char[memowl*512];}
- if (!memow) {dbfer(NOMEMSP); return("");}
- db->memow=memow;
- db->memowl=memowl;
- return(getfield(n,trimflag));
- }
- }
- else {*fieldwork=0; return fieldwork;}
-
- if (trimflag) return(rtrim(memow)); return(memow);
- }
- }
-
- if (trimflag) return(rtrim(fieldwork));
- return(fieldwork);
- }
-
- // Get field by field name
-
- char *record::getfield(char *name,int trimflag)
- {
- field *fld;
- long grn=0;
-
- if (fld=db->getfield(name)) grn=fld->getnumber();
-
- return(getfield(grn,trimflag));
- }
-
- /******************** Set Field Operations *********************/
-
- int record::doset(char *value,field *fld)
- {
- char *sp=value;
- char *fp=rbp+fld->recpos;
-
- for(int i=0; i<fld->len; i++) *fp++=(*sp) ? *sp++ : ' ';
- return 0;
- }
-
- int record::setfield(int num,char *value)
- {
- field *fld;
- int i,obp;
- char *fp;
-
- if (!(fld=db->getfield(num))) return RECNOTSET;
- switch(fld->gettype())
- {
- case 'C' : return doset(value,fld);
-
- case 'D' : if (strlen(value)!=8) return RECNOTSET;
- for(i=0; i<strlen(value); i++)
- if (!isdigit(value[i])) return RECNOTSET;
- return doset(value,fld);
-
- case 'L' : strupr(value);
- if (*value=='T' || *value=='F' ||
- *value=='Y' || *value=='N') return doset(value,fld);
-
- case 'M' : fp=rbp+fld->recpos; *fp='~'; *(char **)(fp+1)=value; return 0;
-
- default : return RECNOTSET;
- }
- }
-
- int record::setfield(int num,double value)
- {
- field *fld=db->getfield(num);
-
- if (!fld || fld->gettype()!='N') return RECNOTSET;
-
- char ws[128],ss[128];
- int i,nex,wslen;
-
- sprintf(ss,"%%.%df",fld->getrdp()); // May need %f here ?
- wslen=sprintf(ws,ss,value);
- nex=fld->getlen()-wslen;
- if (nex>0) {memmove(ws+nex,ws,wslen+1); for(i=0; i<nex; i++) ws[i]=' ';}
- return doset(ws,fld);
- }
-
- int record::setfield(char *name,double value)
- {
- field *fld=db->getfield(name);
-
- if (!fld) return RECNOTSET;
-
- return setfield(fld->getnumber(),value);
- }
-
- int record::setfield(char *name,char *value)
- {
- field *fld=db->getfield(name);
-
- if (!fld) return RECNOTSET;
-
- return setfield(fld->getnumber(),value);
- }
-
- /******************** Write Record Operations ******************/
-
- int record::write(int type)
- {
- index *ip;
- char res[128],reso[128]; // index results
- int dum;
- int nb; // No. of bytes written to file
- long fp; // Position in file to write record
- record *upp; // Pointer to records using index
- long urn; // record no. of " " "
- int e=1; // error number
- int ret; // Return value
-
- if (rn<1 && type==OVER) return NOWRUNR;
-
- if (db->dbtp) wmemo(type); // Check if any memos need writing
-
- if (type==OVER) // Overwrite, set position in dbf file
- {
- fp=db->recstart+db->reclen*(rn-1);
- Fseek(db->dbfp,fp,SEEK_SET);
- nb=Fwrite(recbuf,1,db->reclen,db->dbfp);
-
- ip=db->findex;
- record *dbr=db->firstrec;
- while(dbr)
- {
- if (dbr->rn==rn && dbr!=this)
- {
- memmove(dbr->recbufo,recbuf,db->reclen+1);
- memmove(dbr->recbuf,recbuf,db->reclen+1);
- dbr->delstate=delstate;
- }
- dbr=dbr->next;
- }
- while(ip)
- {
- memmove(db->exwork,ip->tindexp,512);
- rbp=recbufo;
- eval(reso,dum);
- rbp=recbuf;
- eval(res,dum);
- if (memcmp(res,reso,ip->topind->explen))
- {
- delkey(reso,ip);
- inskey(res,ip);
-
- upp=ip->firstrec; // Update record keys
- while(upp)
- {
- if (upp->rn>=0)
- {
- urn=upp->rn;
- upp->eval(res,dum);
- if (upp->selkey(res,READIND,ip->indtype)) goto error;
- while(upp->rn!=urn) if (upp->selkey()) {e=2; goto error;}
- }
- upp=upp->nextind;
- }
- }
- ip=ip->next;
- }
- }
- else // Add a new record at the file end
- {
- rn=++(db->nrec);
-
- ip=db->findex;
- while(ip)
- {
- memmove(db->exwork,ip->tindexp,512); // copy over index epression
- eval(res,dum);
- inskey(res,ip);
-
- upp=ip->firstrec; // Update record keys
- while(upp)
- {
- if (upp->rn>=0)
- {
- urn=upp->rn;
- upp->eval(res,dum);
- if (upp->selkey(res,READIND,ip->indtype)) {e=3; goto error;}
- while(upp->rn!=urn) if (upp->selkey()) {e=4; goto error;}
- }
- upp=upp->nextind;
- }
- ip=ip->next;
- }
-
- fp=db->recstart+db->reclen*(rn-1);
- Fseek(db->dbfp,fp,SEEK_SET);
- nb=Fwrite(recbuf,1,db->reclen,db->dbfp);
- }
-
- memmove(recbufo,recbuf,db->reclen+1);
- ret=(nb==db->reclen) ? 0 : WRFAIL;
- db->change=1;
-
- return ret;
-
- error : // Fatal error in index write !
-
- dbfer(ERINDW);
- // printf("\nError code %d in index jig, rn %d\n",e,urn);
- return WRFAIL;
- }
-
- // This routine checks to see if the record has any memos to write
-
- void record::wmemo(int type)
- {
- char *ws=new char[512];
-
- for(int i=1; i<=db->nfield; i++)
- {
- field *fld=db->getfield(i);
- if (fld->gettype()=='M') // Memo field
- {
- char *mp=recbuf+fld->recpos;
-
- if (*mp=='~') // A new memo field has been written
- {
- long bp=0; // New buffer pointer
- unsigned int len; // Length of new memo
- char *memo=*(char **)(mp+1);
-
- if (len=strlen(memo))
- {
- if (len<=510) bp=atol(recbufo+fld->recpos); // Fit in the old block ?
- if (type==NEW || !bp) // Must create a new block
- {
- Fseek(db->dbtp,0,SEEK_SET); Fread(ws,1,512,db->dbtp);
- bp=*(long *)ws;
- *(long *)ws=bp+len/512+1;
- Fseek(db->dbtp,0,SEEK_SET); Fwrite(ws,1,512,db->dbtp);
- }
- Fseek(db->dbtp,(long)(bp*512L),SEEK_SET);
- Fwrite(memo,1,len,db->dbtp);
- fputc(0x1a,db->dbtp); fputc(0x1a,db->dbtp); len+=2;
- memset(ws,' ',512);
- if (len & 0x1ff) Fwrite(ws,1,(512-(len & 0x1ff)),db->dbtp);
- sprintf(ws,"%010ld",bp);
- memcpy(mp,ws,10);
- }
- else memset(mp,'0',10);
- }
- }
- }
-
- delete ws;
- }
-
- /****************************************************************
-
- EVAL routines
-
- *****************************************************************/
-
- int record::eval(char *expr,void *result,int &rtype)
- {
- char *wsp;
-
- if (!db->ex)
- {
- db->ex=new expval(db);
- db->exwork=new char[512];
- }
- if (!db->ex || !db->exwork || db->ex->erflag==2) return 0;
- db->ex->erflag=0;
-
- wsp=db->exwork;
- db->ex->exetoken(expr,&wsp);
- if (db->ex->erflag==1) {db->ex->erflag=3; return 0;} // show tokeniser error
- return eval(result,rtype);
- }
-
- int record::eval(void *result,int &rtype)
- {
- op *rv;
- char *wsp;
-
- if (!db->ex || db->ex->erflag>1) return 0; // Fatal or tokeniser error
-
- wsp=db->exwork;
- indflg=0;
- rv=db->ex->exeval(&wsp,this);
- if (db->ex->erflag) return 0;
- rtype=rv->optype;
- if (rtype==OPINT) *(double *)result=rv->num;
- if (rtype==OPSTR) strcpy((char *)result,rv->str);
- if (rtype==OPDATE) strcpy((char *)result,rv->date);
- if (rtype==OPLOG)
- {*(char *)result=(rv->num) ? 'T' : 'F'; ((char *)result)[1]=0;}
- return 1;
- }
-
-
-